#!/usr/bin/env ruby
####
#
# Copyright 2007 B. Chandler Carruth
#
# Licensed under the Apache License, Version 2
# .0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
####
#
# ./test/util/file_change_test.rb
#
####

require( 'test/unit' )
require( 'fileutils' )
require( 'pathname' )

# path adjustment
$:.unshift( File.join( File.dirname( __FILE__ ), '..', '..', 'lib' ) )

# pull in libraries
require( 'rcons/environment' )
require( 'rcons/util/file_change_module' )

class UtilFileChangeTest < Test::Unit::TestCase
  class DummyTarget
    include RCons::FileChangeModule

    attr_reader( :env, :scratch_path )

    def initialize( env )
      @build_env = env
      @scratch_path = '$(BUILD_ROOT)/file_change_test/scratch'
    end
  end


  def setup
    # test env to be used for the target, etc
    @env = RCons::Environment.new( 'test', File.dirname( __FILE__ ), File.dirname( __FILE__ ) )

    # if test generated files already exist, tear down
    if (FileTest::exists?(@env.expand("$(BUILD_ROOT)/file_change_test")))
      FileUtils.remove_entry_secure( @env.expand("$(BUILD_ROOT)/file_change_test") )
    end
    if (FileTest::exists?(@env.expand("$(BUILD_ROOT)/ex1_file.c")))
      FileUtils.rm( @env.expand("$(BUILD_ROOT)/ex1_file.c") )
    end

    # Create test c file
    writefile = File.open( @env.expand( "$(BUILD_ROOT)/ex1_file.c" ), File::TRUNC | File::CREAT | File::WRONLY )
    writefile.puts "#include <stdlib.h>"
    writefile.puts ""
    writefile.puts "int main()"
    writefile.puts "{"
    writefile.puts "  return 1;"
    writefile.puts "}"
    writefile.close

    @dummy = DummyTarget.new( @env )
  end

  def teardown
    # tear down files generated by test
    if (FileTest::exists?(@env.expand("$(BUILD_ROOT)/file_change_test")))
      FileUtils.remove_entry_secure( @env.expand("$(BUILD_ROOT)/file_change_test") )
    end
    if (FileTest::exists?(@env.expand("$(BUILD_ROOT)/ex1_file.c")))
      FileUtils.rm( @env.expand("$(BUILD_ROOT)/ex1_file.c") )
    end

    @dummy = nil
    @env = nil
  end

  # test whether or not digest file was created containing a file path and a checksum
  def test_update_digest
    @dummy.update_digest( File.join( File.dirname( __FILE__ ), 'ex1_file.c' ) )

    # open digest file and read contents into an array
    fileread = File.open( @env.expand( "$(BUILD_ROOT)/file_change_test/scratch/digests" ) )
    filecontents = fileread.readlines()
    fileread.close

    # make sure the entire file was only one line
    assert_equal(1, filecontents.length)

    filepath = File.expand_path( File.join( File.dirname( __FILE__ ), 'ex1_file.c' ) )

    # test to see if file contains a file path, then a checksum
     assert_match(/\A#{filepath}(?!\\) \w+\Z/, filecontents[0], "Structure of digest file incorrect" )
  end

  # tests to make sure the checksum changes when the file changes
  def test_file_change
    # updates the digest of ex1_file.c
    @dummy.update_digest( File.join( File.dirname( __FILE__ ), 'ex1_file.c' ) )

    # opens the digest and stores the checksum of ex1_file.c into 'originalchecksum'
    fileread = File.open( @env.expand( "$(BUILD_ROOT)/file_change_test/scratch/digests" ) )
    filecontents = fileread.readlines(" ")
    fileread.close
    originalchecksum = filecontents[1]

    # deletes and recreates ex1_file.c to have different functionality
    if (FileTest::exists?(@env.expand("$(BUILD_ROOT)/ex1_file.c")))
      FileUtils.rm( @env.expand("$(BUILD_ROOT)/ex1_file.c") )
    end

    writefile = File.open( @env.expand( "$(BUILD_ROOT)/ex1_file.c" ), File::TRUNC | File::CREAT | File::WRONLY )
    writefile.puts "#include <stdlib.h>"
    writefile.puts ""
    writefile.puts "int main()"
    writefile.puts "{"
    writefile.puts "  cout << hi mom << endl; "
    writefile.puts "  return 0;"
    writefile.puts "}"
    writefile.close

    # updates the digest of the newly modified ex1_file.c
    @dummy.update_digest( File.join( File.dirname( __FILE__ ), 'ex1_file.c' ) )

    # opens the digest and stores the checksum of the new ex1_file.c into 'newchecksum'
    fileread = File.open( @env.expand( "$(BUILD_ROOT)/file_change_test/scratch/digests" ) )
    filecontents = fileread.readlines(" ")
    fileread.close
    newchecksum = filecontents[1]

    # checks to make sure the old checksum and the new checksum are not equal
    assert_not_equal(newchecksum, originalchecksum, "File updated, but file_change_module did not notice. Error!")
  end
end

